/**
 * 
 */
package datamodel.tree.sequential;

import java.util.Vector;
import datamodel.tree.Tree;
import datamodel.tree.TreeNode;

/**
 * An implementation of the tree interface.<br>
 * uses a sequential construction
 * 
 * @author Jakob Karolus, Kevin Munk
 * @version 1.0
 * 
 */
public class SequentialTree extends Tree {
	
	private Vector<TreeNode> tree = new Vector<TreeNode>();
	private int currentPosition = 0;
	
	@Override
	public boolean moveToLeftNode() {
		if (this.hasLeftNode()){
			this.currentPosition = this.getLeftChildPosition();
			return true;
		}
		return false;
	}

	@Override
	public boolean moveToRightNode() {
		if(this.hasRightNode()){
			this.currentPosition = this.getRightChildPosition();
			return true;
		}
		return false;
	}

	@Override
	public boolean moveToParentNode() {
		if (this.hasParentNode()){
			this.currentPosition = this.getParentPosition();
			return true;
		}
		return false;
	}

	@Override
	public boolean hasLeftNode() {
		int lcPos = this.getLeftChildPosition();
		if(lcPos < 0 || lcPos >= this.tree.size()){
			return false;
		} else if (this.tree.get(lcPos) != null){
			return true;
		}
		return false;
	}

	@Override
	public boolean hasRightNode() {
		int rcPos = this.getRightChildPosition();
		if (rcPos < 0 || rcPos >= this.tree.size()){
			return false;
		} else if (this.tree.get(rcPos) != null){
			return true;
		}
		return false;
	}

	@Override
	public boolean hasParentNode() {
		int parentPos = this.getParentPosition();
		if (parentPos < 0 || parentPos >= this.tree.size()){
			return false;
		} else if (this.tree.get(parentPos) != null){
			return true;
		}
		return false;
	}

	@Override
	public boolean setLeftNode(TreeNode node) {
		return this.setNodeAt(this.getLeftChildPosition(), node);
	}

	@Override
	public boolean setRightNode(TreeNode node) {
		return this.setNodeAt(this.getRightChildPosition(), node);
	}

	@Override
	public void setCurrentNode(TreeNode node) {
		if(this.tree.size() == 0){
			this.tree.add(node);
			currentPosition = 0;
		} else {
			this.setNodeAt(this.currentPosition, node);
		}
	}

	@Override
	public TreeNode getCurrentNode() {
		if (this.tree.size() == 0){
			return null;
		}
		return this.tree.get(currentPosition);
	}

	@Override
	public boolean moveToRoot() {
		if ((this.tree.size() >= 1) && (tree.get(0) != null)){
			this.currentPosition = 0;
			return true;
		}
		return false;
	}

	@Override
	public void clearTree() {
		this.tree.clear();
		this.currentPosition = 0;
		
	}
	
	/**
	 * Sets a given TreeNode node at the given position pos in this SequentialTree
	 * @param pos
	 * @param node
	 * @return true if successful, false otherwise (no root set)
	 */
	private boolean setNodeAt(int pos, TreeNode node){
		// If the tree is not empty and there exists a root
		if ((this.tree.size() >= 1) && (this.tree.get(0) != null)){
			if (pos < this.tree.size()){
				this.tree.setElementAt(node, pos);
			} else {
				final int TREE_SIZE = this.tree.size();
				for (int i = 0; i < pos - TREE_SIZE; i++){
					this.tree.add(null);
				}
				this.tree.add(node);
			}
			return true;
		}
		return false;
	}
	
	/**
	 * Determines the index of the right child of the current node
	 * @return the index of the right child of the current node
	 */
	private int getRightChildPosition(){
		return 2 * (this.currentPosition + 1);
	}
	
	/**
	 * Determines the index of the left child of the current node
	 * @return the index of the left child of the current node
	 */
	private int getLeftChildPosition(){
		return (2 * (this.currentPosition + 1)) - 1;
	}
	
	/**
	 * Determines the index of the parent of the current node
	 * @return the index of the parent of the current node
	 */
	private int getParentPosition(){
		return ((this.currentPosition + 1) / 2) - 1;
	}
		

}
